package com.dw.article.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dw.article.mapper.mp.ArticleUserMapper;
import com.dw.article.redis.RedisConfig;
import com.dw.article.service.ArticleMappingService;
import com.dw.article.service.CategoryInfoService;
import com.dw.article.service.LabelInfoService;
import com.dw.article.utils.LoginUtil;
import com.dw.model.article.dtos.user.AddArticleUserDTO;
import com.dw.model.article.entitys.ArticleInfo;
import com.dw.model.article.entitys.ArticleUser;
import com.dw.article.service.ArticleUserService;
import com.dw.model.article.entitys.CategoryInfo;
import com.dw.model.article.entitys.LabelInfo;
import com.dw.model.article.vos.article.GetCountVO;
import com.dw.model.article.vos.article.QueryUserArticleVO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文章用户关系表(ArticleUser)表服务实现类
 *
 * @author makejava
 * @since 2024-10-09 20:12:53
 */
@Service("articleUserService")
public class ArticleUserServiceImpl extends ServiceImpl<ArticleUserMapper, ArticleUser> implements ArticleUserService {

    @Resource
    private ArticleMappingService articleMappingService;

    @Resource
    private CategoryInfoService categoryInfoService;

    @Resource
    private LabelInfoService labelInfoService;

    @Resource
    private RedisTemplate redisTemplate;

    private final String ARTICLE_LIKED_KEY = "article.liked";

    private final String ARTICLE_LIKED_COUNT_KEY = "article.liked.count";

    private final String ARTICLE_LIKED_DETAIL_KEY = "article.liked.detail";

    private final String ARTICLE_STAR_KEY = "article.star";

    private final String ARTICLE_STAR_COUNT_KEY = "article.star.count";

    private final String ARTICLE_STAR_DETAIL_KEY = "article.star.detail";

    private final String ARTICLE_SHARED_KEY = "article.shared";

    private final String ARTICLE_SHARED_COUNT_KEY = "article.shared.count";

    private final String ARTICLE_SHARED_DETAIL_KEY = "article.shared.detail";

    private final String ARTICLE_RANK_KEY = "article.rank";

    private final String LABEL_RANK_KEY = "label.rank";

    private final String CATEGORY_RANK_KEY = "category.rank";

    /**
     * 点赞
     * @param addArticleUserDTO
     */
    @Override
    public void like(AddArticleUserDTO addArticleUserDTO){
        Long articleId = addArticleUserDTO.getArticleId();
        long userId = Long.parseLong(LoginUtil.getLoginId());
        Integer isLiked = addArticleUserDTO.getIsLiked();
        String hashKey = articleId + ":" + userId;
        redisTemplate.opsForHash().put(ARTICLE_LIKED_KEY, hashKey, isLiked);
        String detailKey = ARTICLE_LIKED_DETAIL_KEY + "." + articleId + "." + userId;
        String countKey = ARTICLE_LIKED_COUNT_KEY + "." + articleId;
        // 根据文章id查询关联的分类和标签
        List<Long> categoryIds = articleMappingService.queryById(articleId).getCategoryIds();
        List<Long> labelIds = articleMappingService.queryById(articleId).getLabelIds();
        if(isLiked == 1){
            redisTemplate.opsForValue().increment(countKey, 1);
            redisTemplate.opsForValue().set(detailKey, 1);
            // 增加文章热度
            redisTemplate.opsForZSet().incrementScore(ARTICLE_RANK_KEY, articleId, 10);
            // 为相关分类增加热度
            categoryIds.forEach(categoryId -> {
                redisTemplate.opsForZSet().incrementScore(CATEGORY_RANK_KEY, categoryId, 10);
            });
            // 为相关标签增加热度
            labelIds.forEach(labelId -> {
                redisTemplate.opsForZSet().incrementScore(LABEL_RANK_KEY, labelId, 10);
            });
        } else {
            Number result = (Number) redisTemplate.opsForValue().get(detailKey);
            if(result == null || result.longValue() <= 0){
                return;
            }
            redisTemplate.opsForValue().increment(countKey, -1);
            redisTemplate.delete(detailKey);
            // 降低文章热度
            redisTemplate.opsForZSet().incrementScore(ARTICLE_RANK_KEY, articleId, -10);
            // 为相关分类降低热度
            categoryIds.forEach(categoryId -> {
                redisTemplate.opsForZSet().incrementScore(CATEGORY_RANK_KEY, categoryId, -10);
            });
            // 为相关标签降低热度
            labelIds.forEach(labelId -> {
                redisTemplate.opsForZSet().incrementScore(LABEL_RANK_KEY, labelId, -10);
            });
        }
    }

    /**
     * 收藏
     * @param addArticleUserDTO
     */
    @Override
    public void star(AddArticleUserDTO addArticleUserDTO) {
        Long articleId = addArticleUserDTO.getArticleId();
        long userId = Long.parseLong(LoginUtil.getLoginId());
        Integer isStar = addArticleUserDTO.getIsStar();
        String hashKey = articleId + ":" + userId;
        redisTemplate.opsForHash().put(ARTICLE_STAR_KEY, hashKey, isStar);
        String detailKey = ARTICLE_STAR_DETAIL_KEY + "." + articleId + "." + userId;
        String countKey = ARTICLE_STAR_COUNT_KEY + "." + articleId;
        // 根据文章id查询关联的分类和标签
        List<Long> categoryIds = articleMappingService.queryById(articleId).getCategoryIds();
        List<Long> labelIds = articleMappingService.queryById(articleId).getLabelIds();
        if(isStar == 1){
            redisTemplate.opsForValue().increment(countKey, 1);
            redisTemplate.opsForValue().set(detailKey, 1);
            // 增加文章热度
            redisTemplate.opsForZSet().incrementScore(ARTICLE_RANK_KEY, articleId, 50);
            // 为相关分类增加热度
            categoryIds.forEach(categoryId -> {
                redisTemplate.opsForZSet().incrementScore(CATEGORY_RANK_KEY, categoryId, 50);
            });
            // 为相关标签增加热度
            labelIds.forEach(labelId -> {
                redisTemplate.opsForZSet().incrementScore(LABEL_RANK_KEY, labelId, 50);
            });
        } else {
            Number result = (Number) redisTemplate.opsForValue().get(detailKey);
            if(result == null || result.longValue() <= 0){
                return;
            }
            redisTemplate.opsForValue().increment(countKey, -1);
            redisTemplate.delete(detailKey);
            // 降低文章热度
            redisTemplate.opsForZSet().incrementScore(ARTICLE_RANK_KEY, articleId, -50);
            // 为相关分类降低热度
            categoryIds.forEach(categoryId -> {
                redisTemplate.opsForZSet().incrementScore(CATEGORY_RANK_KEY, categoryId, -50);
            });
            // 为相关标签降低热度
            labelIds.forEach(labelId -> {
                redisTemplate.opsForZSet().incrementScore(LABEL_RANK_KEY, labelId, -50);
            });
        }
    }

    /**
     * 转发
     * @param addArticleUserDTO
     */
    @Override
    public void share(AddArticleUserDTO addArticleUserDTO) {
        Long articleId = addArticleUserDTO.getArticleId();
        long userId = Long.parseLong(LoginUtil.getLoginId());
        Integer isShared = addArticleUserDTO.getIsShared();
        String hashKey = articleId + ":" + userId;
        redisTemplate.opsForHash().put(ARTICLE_SHARED_KEY, hashKey, isShared);
        String detailKey = ARTICLE_SHARED_DETAIL_KEY + "." + articleId + "." + userId;
        String countKey = ARTICLE_SHARED_COUNT_KEY + "." + articleId;
        // 根据文章id查询关联的分类和标签
        List<Long> categoryIds = articleMappingService.queryById(articleId).getCategoryIds();
        List<Long> labelIds = articleMappingService.queryById(articleId).getLabelIds();
        if(isShared == 1){
            redisTemplate.opsForValue().increment(countKey, 1);
            redisTemplate.opsForValue().set(detailKey, 1);
            // 增加文章热度
            redisTemplate.opsForZSet().incrementScore(ARTICLE_RANK_KEY, articleId, 30);
            // 为相关分类增加热度
            categoryIds.forEach(categoryId -> {
                redisTemplate.opsForZSet().incrementScore(CATEGORY_RANK_KEY, categoryId, 30);
            });
            // 为相关标签增加热度
            labelIds.forEach(labelId -> {
                redisTemplate.opsForZSet().incrementScore(LABEL_RANK_KEY, labelId, 30);
            });
        } else {
            Number result = (Number) redisTemplate.opsForValue().get(detailKey);
            if(result == null || result.longValue() <= 0){
                return;
            }
            redisTemplate.opsForValue().increment(countKey, -1);
            redisTemplate.delete(detailKey);
            // 降低文章热度
            redisTemplate.opsForZSet().incrementScore(ARTICLE_RANK_KEY, articleId, -30);
            // 为相关分类降低热度
            categoryIds.forEach(categoryId -> {
                redisTemplate.opsForZSet().incrementScore(CATEGORY_RANK_KEY, categoryId, -30);
            });
            // 为相关标签降低热度
            labelIds.forEach(labelId -> {
                redisTemplate.opsForZSet().incrementScore(LABEL_RANK_KEY, labelId, -30);
            });
        }
    }

    /**
     * 获取文章点赞收藏转发数量
     */
    @Override
    public GetCountVO getArticleUserCount(Long articleId) {
        GetCountVO getCountVO = new GetCountVO();
        // 查询点赞数
        String likedKey = ARTICLE_LIKED_COUNT_KEY + "." + articleId;
        Number likedCount = (Number) redisTemplate.opsForValue().get(likedKey);
        if(likedCount == null){
            likedCount = 0;
        }
        getCountVO.setLikeCount(likedCount.longValue());
        // 查询收藏数
        String starKey = ARTICLE_STAR_COUNT_KEY + "." + articleId;
        Number starCount = (Number) redisTemplate.opsForValue().get(starKey);
        if(starCount == null){
            starCount = 0;
        }
        getCountVO.setStarCount(starCount.longValue());
        // 查询转发数
        String sharedKey = ARTICLE_SHARED_COUNT_KEY + "." + articleId;
        Number sharedCount = (Number) redisTemplate.opsForValue().get(sharedKey);
        if(sharedCount == null){
            sharedCount = 0;
        }
        getCountVO.setShareCount(sharedCount.longValue());
        return getCountVO;
    }

    /**
     * 查询当前用户是否点赞收藏转发
     */
    @Override
    public QueryUserArticleVO queryUserArticle(Long articleId) {
        long userId = Long.parseLong(LoginUtil.getLoginId());
        QueryUserArticleVO queryUserArticleVO = new QueryUserArticleVO();
        // 点赞
        String likedKey = ARTICLE_LIKED_DETAIL_KEY + "." + articleId + "." + userId;
        Number liked = (Number) redisTemplate.opsForValue().get(likedKey);
        if(liked != null && liked.longValue() > 0){
            queryUserArticleVO.setIsLiked(1);
        }
        // 收藏
        String starKey = ARTICLE_STAR_DETAIL_KEY + "." + articleId + "." + userId;
        Number star = (Number) redisTemplate.opsForValue().get(starKey);
        if(star != null && star.longValue() > 0){
            queryUserArticleVO.setIsStar(1);
        }
        // 转发
        String sharedKey = ARTICLE_SHARED_DETAIL_KEY + "." + articleId + "." + userId;
        Number shared = (Number) redisTemplate.opsForValue().get(sharedKey);
        if(shared != null && shared.longValue() > 0){
            queryUserArticleVO.setIsShared(1);
        }
        return queryUserArticleVO;
    }

    /**
     * 查询热门文章
     * @return
     */
    @Override
    public List<ArticleInfo> queryHotArticle() {
        // 查询热度前10名的所有文章
        Set<ZSetOperations.TypedTuple<Long>> set = redisTemplate.opsForZSet().reverseRangeWithScores(ARTICLE_RANK_KEY, 0, 9);
        if(CollectionUtils.isEmpty(set)){
            return Collections.emptyList();
        }
        return set.stream().map(rank -> {
            ArticleInfo articleInfo = new ArticleInfo();
            articleInfo.setArticleFire(rank.getScore().longValue());
            articleInfo.setLeiId(rank.getValue());
            return articleInfo;
        }).collect(Collectors.toList());
    }

    /**
     * 查询热门标签
     */
    public List<LabelInfo> queryHotLabel(){
        // 查询前10名的所有标签
        Set<ZSetOperations.TypedTuple<Long>> set = redisTemplate.opsForZSet().reverseRangeWithScores(LABEL_RANK_KEY, 0, 9);
        if(CollectionUtils.isEmpty(set)){
            return Collections.emptyList();
        }
        List<LabelInfo> collect = set.stream().map(rank -> {
            LabelInfo labelInfo = new LabelInfo();
            labelInfo.setLabelFire(rank.getScore().longValue());
            labelInfo.setLeiId(rank.getValue());
            return labelInfo;
        }).collect(Collectors.toList());
        collect.forEach(labelInfo -> {
            if(labelInfo.getLeiId() != null){
                LabelInfo labelInfo1 = labelInfoService.queryLabelNameById(labelInfo.getLeiId());
                labelInfo.setLabelName(labelInfo1.getLabelName());
            }
        });
        return collect;
    }

    /**
     * 查询热门分类
     */
    public List<CategoryInfo> queryHotCategory(){
        // 查询前10名的所有分类
        Set<ZSetOperations.TypedTuple<Long>> set = redisTemplate.opsForZSet().reverseRangeWithScores(CATEGORY_RANK_KEY, 0, 9);
        if(CollectionUtils.isEmpty(set)){
            return Collections.emptyList();
        }
        List<CategoryInfo> collect = set.stream().map(rank -> {
            CategoryInfo categoryInfo = new CategoryInfo();
            categoryInfo.setCategoryFire(rank.getScore().longValue());
            categoryInfo.setLeiId(rank.getValue());
            return categoryInfo;
        }).collect(Collectors.toList());
        collect.forEach(categoryInfo -> {
            CategoryInfo categoryInfo1 = categoryInfoService.queryCategoryNameById(categoryInfo.getLeiId());
            categoryInfo.setCategoryName(categoryInfo1.getCategoryName());
        });
        return collect;
    }

    /**
     * 查询用户点赞
     */
    @Override
    public List<Long> getMyLiked(AddArticleUserDTO addArticleUserDTO) {
        Map<Object, Object> likedEntires = redisTemplate.opsForHash().entries(ARTICLE_LIKED_KEY);
        return likedEntires.keySet().stream().filter(o -> {
            String[] keyArr = o.toString().split(":");
            Long userId = Long.valueOf(keyArr[1]);
            return userId.equals(addArticleUserDTO.getUserId());
        }).map(o -> Long.valueOf(o.toString().split(":")[0])).collect(Collectors.toList());
    }

    /**
     * 查询用户收藏
     */
    @Override
    public List<Long> getMyStar(AddArticleUserDTO addArticleUserDTO) {
        Map<Object, Object> starEntires = redisTemplate.opsForHash().entries(ARTICLE_STAR_KEY);
        return starEntires.keySet().stream().filter(o -> {
            String[] keyArr = o.toString().split(":");
            Long userId = Long.valueOf(keyArr[1]);
            return userId.equals(addArticleUserDTO.getUserId());
        }).map(o -> Long.valueOf(o.toString().split(":")[0])).collect(Collectors.toList());
    }

    /**
     * 查询用户分享
     */
    @Override
    public List<Long> getMyShared(AddArticleUserDTO addArticleUserDTO) {
        Map<Object, Object> sharedEntires = redisTemplate.opsForHash().entries(ARTICLE_SHARED_KEY);
        return sharedEntires.keySet().stream().filter(o -> {
            String[] keyArr = o.toString().split(":");
            Long userId = Long.valueOf(keyArr[1]);
            return userId.equals(addArticleUserDTO.getUserId());
        }).map(o -> Long.valueOf(o.toString().split(":")[0])).collect(Collectors.toList());
    }


}

